package geppetto.cat.alignments;

public class AlignmentSymetrization {

	public static AlignmentsSet intersect(AlignmentsSet forward,
			AlignmentsSet backward) {
		AlignmentsSet inter = new AlignmentsSet();
		for (int i = 0; i < forward.size(); i++)
			inter.addAlignment(intersect(forward.get(i), backward.get(i)));
		return inter;
	}

	public static Alignment intersect(Alignment sf, Alignment fs) {
		Alignment inter = new Alignment(sf.getSentenceNumber(), sf
				.getSentenceSource(), sf._sourceLen, sf._foreignLen);
		for (int k = 0; k < sf.getSourceLenght(); k++) {
			for (int l = 0; l < sf.getForeignLenght(); l++) {
				if (sf.hasPosition(k, l) && fs.hasPosition(l, k))
					inter.add(k, l, (byte) 3);
			}
		}
		return inter;
	}

	public static Alignment union(Alignment sf, Alignment fs) {
		Alignment union = new Alignment(sf.getSentenceNumber(), sf
				.getSentenceSource(), sf._sourceLen, sf._foreignLen);
		for (int k = 0; k < sf.getSourceLenght(); k++) {
			for (int l = 0; l < sf.getForeignLenght(); l++) {
				if (sf.hasPosition(k, l) && fs.hasPosition(l, k))
					union.add(k, l, (byte) 3);
				else if (sf.hasPosition(k, l) || fs.hasPosition(l, k))
					union.add(k, l, (byte) 4);
			}
		}
		return union;
	}

	public static AlignmentsSet union(AlignmentsSet forward,
			AlignmentsSet backward) {
		AlignmentsSet union = new AlignmentsSet();
		for (int i = 0; i < forward.size(); i++)
			union.addAlignment(union(forward.get(i), backward.get(i)));
		return union;
	}

	// /PSEUDO-CODE from the moses home page
	// / http://www.statmt.org/moses/?n=FactoredTraining.AlignWords
	/*
	 * GROW-DIAG-FINAL(e2f,f2e): neighboring =
	 * ((-1,0),(0,-1),(1,0),(0,1),(-1,-1),(-1,1),(1,-1),(1,1)) alignment =
	 * intersect(e2f,f2e); GROW-DIAG(); FINAL(e2f); FINAL(f2e);
	 * 
	 * GROW-DIAG(): iterate until no new points added for english word e = 0 ...
	 * en for foreign word f = 0 ... fn if ( e aligned with f ) for each
	 * neighboring point ( e-new, f-new ): if ( ( e-new not aligned and f-new
	 * not aligned ) and ( e-new, f-new ) in union( e2f, f2e ) ) add alignment
	 * point ( e-new, f-new ) FINAL(a): for english word e-new = 0 ... en for
	 * foreign word f-new = 0 ... fn if ( ( e-new not aligned or f-new not
	 * aligned ) and ( e-new, f-new ) in alignment a ) add alignment point (
	 * e-new, f-new )
	 */

	public static AlignmentsSet growDiagAux(AlignmentsSet forward,
			AlignmentsSet backward, AlignmentsSet inter, AlignmentsSet union) {
		AlignmentsSet growDiag = new AlignmentsSet();
		for (int i = 0; i < forward.size(); i++)
			growDiag.addAlignment(growDiagAux(forward.get(i), backward.get(i),
					inter.get(i), union.get(i)));
		return growDiag;
	}

	public static Alignment growDiagAux(Alignment sf, Alignment fs,
			Alignment inter, Alignment union) {
		Alignment grow = new Alignment(inter);
		boolean newPointsAdded = true;

		while (newPointsAdded) {
			for (int sourceIndex = 0; sourceIndex < sf.getSourceLenght(); sourceIndex++) { // Source
																							// index
				for (int foreignIndex = 0; foreignIndex < sf.getForeignLenght(); foreignIndex++) { // foreign
																									// index
					if (grow.hasPosition(sourceIndex, foreignIndex)) {
						for (int sourceCounter = -1; sourceCounter <= 1; sourceCounter++) { // Source
																							// Counter
							for (int foreignCounter = -1; foreignCounter <= 1; foreignCounter++) { // Foreign
																									// Counter
								if (!(sourceCounter == 0 && foreignCounter == 0)) { // Dont
																					// use
																					// same
																					// points
									// System.out.println("Estou na posicao " +
									// (k+j) + " " + (l+i));
									if ((!grow
											.foreignWordIsAligned(foreignIndex
													+ foreignCounter) && // foreign
																			// word
																			// not
																			// aligned
									!grow.sourceWordIsAligned(sourceIndex
											+ sourceCounter)) // source word
																// not aligned
											&& union.hasPosition(sourceIndex
													+ sourceCounter,
													foreignIndex
															+ foreignCounter)) { // but
																					// the
																					// pair
																					// belongs
																					// to
																					// the
																					// union
										grow.add(sourceIndex + sourceCounter,
												foreignIndex + foreignCounter,
												(byte) 5); // add the alignment
									} else
										newPointsAdded = false;
								}
							}
						}
					}
				}
			}
			newPointsAdded = false;

		}

		return grow;
	}

	public static Alignment growDiag(Alignment sf, Alignment fs) {
		return growDiagAux(sf, fs, AlignmentSymetrization.intersect(sf, fs),
				AlignmentSymetrization.union(sf, fs));
	}

	public static AlignmentsSet growDiag(AlignmentsSet forward,
			AlignmentsSet backward) {
		AlignmentsSet inter = intersect(forward, backward);
		AlignmentsSet union = union(forward, backward);
		AlignmentsSet growDiag = growDiagAux(forward, backward, inter, union);
		return growDiag;
	}

	public static AlignmentsSet growDiagFinalAux(AlignmentsSet forward,
			AlignmentsSet backward, AlignmentsSet inter, AlignmentsSet union,
			AlignmentsSet grow) {
		AlignmentsSet growDiagF = new AlignmentsSet();
		for (int i = 0; i < forward.size(); i++)
			growDiagF.addAlignment(growDiagFinalAux(forward.get(i), backward
					.get(i), inter.get(i), union.get(i), grow.get(i)));
		return growDiagF;
	}

	public static Alignment growDiagFinalAux(Alignment sf, Alignment fs,
			Alignment inter, Alignment union, Alignment grow) {
		Alignment growF = new Alignment(grow);

		for (int sourceIndex = 0; sourceIndex < sf.getSourceLenght(); sourceIndex++) {
			for (int foreignIndex = 0; foreignIndex < sf.getForeignLenght(); foreignIndex++) {
				// if(sf.getSentenceNumber() == 9){
				// if((!grow.foreignWordIsAligned(foreignIndex) ||
				// !grow.sourceWordIsAligned(sourceIndex)))
				// System.out.println("Sentence " + sf.getSentenceNumber() +
				// sourceIndex + " " + foreignIndex + " " +
				// grow.foreignWordIsAligned(foreignIndex) +
				// grow.sourceWordIsAligned(sourceIndex));
				// }
				if ((!grow.foreignWordIsAligned(foreignIndex) || !grow
						.sourceWordIsAligned(sourceIndex))
						&& sf.hasPosition(sourceIndex, foreignIndex)) {
					growF.add(sourceIndex, foreignIndex, (byte) 6);
				}
			}
		}

		for (int sourceIndex = 0; sourceIndex < sf.getSourceLenght(); sourceIndex++) {
			for (int foreignIndex = 0; foreignIndex < sf.getForeignLenght(); foreignIndex++) {
				if ((!growF.foreignWordIsAligned(foreignIndex) || !growF
						.sourceWordIsAligned(sourceIndex))
						&& fs.hasPosition(foreignIndex, sourceIndex)) {
					growF.add(sourceIndex, foreignIndex, (byte) 6);
				}
			}
		}

		return growF;

	}

	public static AlignmentsSet growDiagFinal(AlignmentsSet forward,
			AlignmentsSet backward) {
		AlignmentsSet inter = intersect(forward, backward);
		AlignmentsSet union = union(forward, backward);
		AlignmentsSet growDiag = growDiagAux(forward, backward, inter, union);
		return growDiagFinalAux(forward, backward, inter, union, growDiag);
	}

	public static Alignment growDiagFinal(Alignment sf, Alignment fs) {
		Alignment intersect = AlignmentSymetrization.intersect(sf, fs);
		Alignment union = AlignmentSymetrization.union(sf, fs);
		Alignment grow = growDiagAux(sf, fs, intersect, union);
		return growDiagFinalAux(sf, fs, intersect, union, grow);
	}
	
	public static AlignmentsSet softIntersection(AlignmentsSet sf, AlignmentsSet fs, double threshold){
		AlignmentsSet results = new AlignmentsSet();
		for(int i = 0; i < sf.getAlignments().size(); i++){
			results.addAlignment(softIntersection(sf.get(i), fs.get(i), threshold));
		}
		return results;
	}
	
	public static Alignment softIntersection(Alignment sf, Alignment fs, double threshold) {
		Alignment softIntersection = new Alignment(sf._sentenceNumber,sf._sentenceSource,sf._sourceLen,sf._foreignLen);
		for(int si = 0; si < sf._sourceLen; si++){
			for(int fi = 0; fi < sf._foreignLen; fi++){
				double posterior = sf._posteriors[si][fi]*fs._posteriors[fi][si];
				if(posterior > threshold){
					softIntersection.addPosterior(si, fi, posterior);
					softIntersection.add(si, fi);
				}
			}
		}
		return softIntersection;
	}
	
	
	public static AlignmentsSet softUnion(AlignmentsSet sf, AlignmentsSet fs, double threshold){
		AlignmentsSet results = new AlignmentsSet();
		for(int i = 0; i < sf.getAlignments().size(); i++){
			results.addAlignment(softUnion(sf.get(i), fs.get(i), threshold));
		}
		return results;
	}
	
	public static Alignment softUnion(Alignment sf, Alignment fs, double threshold) {
		Alignment softUnion = new Alignment(sf._sentenceNumber,sf._sentenceSource,sf._sourceLen,sf._foreignLen);
		for(int si = 0; si < sf._sourceLen; si++){
			for(int fi = 0; fi < sf._foreignLen; fi++){
				double posterior = (sf._posteriors[si][fi]+fs._posteriors[fi][si])/2;
				if(posterior > threshold){
					softUnion.addPosterior(si, fi, posterior);
					softUnion.add(si, fi);
				}
			}
		}
		return softUnion;
	}
	
	
	
	
	
}
